<?php

namespace App\Http\Model;

use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Redis;

class GroupChat extends Base
{
    protected $table = 'group_chat';
    protected $primaryKey = 'group_chat_id';

    protected $groupChatMemberTable = 'group_chat_member';
    protected $groupChatReqTable = 'group_chat_req';
    protected $groupChatRoomTable = 'group_chat_room';
    protected $groupChatReportTable = 'group_chat_report';
    protected $groupChatUnionTable = 'group_chat_union';
    protected $groupChatFamilyTable = 'group_chat_family';

    protected $redisKeyGroupChatGeneratedUidDB = 'GROUP:CHAT:UID:GENERATED:DB';
    protected $redisKeyGroupChat = 'CACHE:GROUP_CHAT:';
    protected $redisKeyGroupChatMember = 'CACHE:GROUP_CHAT:MEMBER:';
    protected $redisKeyGroupChatBindRoomHash = 'GROUP_CHAT:%u:BIND_ROOM';

    protected $groupPrefix = 'group_';// 群组前缀

    public function __construct(array $attributes = [])
    {
        parent::__construct($this->table, $attributes);
    }

    /**
     * 融云群组ID分割（替换为本地群聊ID）
     *
     * @param $groupId string 融云群组ID
     * @return int
     * */
    public function rcGroupIdReplacePrefix($groupId)
    {
        // $groupChatId = array_values(array_filter(explode($this->groupPrefix, $groupId)));

        $groupChatId = str_replace($this->groupPrefix, '', $groupId);
        if (empty($groupChatId) or !is_numeric($groupChatId)) {
            $groupChatId = 0;
        }

        return intval($groupChatId);
    }

    /**
     * 取出群聊ID池中已生成的群聊UID
     * @return int
     */
    public function generatedGroupChatUid()
    {
        return Redis::LPOP($this->redisKeyGroupChatGeneratedUidDB);
    }

    /**
     * 群聊-创建/更新/删除
     *
     * @param array $data 数据
     * @param string $type 操作类型 默认 insert=创建，update=更新
     * @param int $groupChatId 群聊ID
     * @return bool
     * */
    public function CUDGroupChat($data = [], $type = 'insert', $groupChatId = 0)
    {
        DB::beginTransaction();

        switch ($type) {
            case 'insert':
                $data['created_at'] = time();
                $data['updated_at'] = time();
                $ret = DB::table($this->table)->insertGetId($data);
                if ($ret) {
                    // 增加群聊该成员为群主
                    $CUDGroupChatMember = $this->CUDGroupChatMember([
                        'group_chat_id' => intval($ret),
                        'user_id' => $data['user_id'],
                        'member_type' => 2,
                        'type'=>!empty($data['type']) ? $data['type'] : 0
                    ]);
                    if (!$CUDGroupChatMember) {
                        DB::rollBack();
                        $ret = false;
                    }
                }
                break;
            case 'update':
                $data['updated_at'] = time();
                $ret = DB::table($this->table)->where([$this->primaryKey => $groupChatId])->update($data);
                break;
            case 'delete':
                $ret = DB::table($this->table)->where([$this->primaryKey => $groupChatId])->delete();
                if ($ret) {
                    // 删除群聊所有成员数据
                    $this->CUDGroupChatMember([], 'deleteAll', $groupChatId);

                    // 删除群聊所有请求加入数据
                    DB::table($this->groupChatReqTable)->where(['group_chat_id' => $groupChatId])->delete();

                    // 删除房间与群聊的绑定
                    $this->deleteRoomBindGroupChat($groupChatId);

                    // 删除群聊举报数据
                    $this->CUDGroupChatReport([], 'delete', $groupChatId);
                }
                break;
            default:
                $ret = false;
                break;
        }

        if ($ret) {
            DB::commit();

            if ($groupChatId > 0 and Redis::exists($this->redisKeyGroupChat . $groupChatId)) {
                Redis::DEL($this->redisKeyGroupChat . $groupChatId);
            }
        }

        return $ret;
    }

    /**
     * 查询群聊列表
     * @param array $condition 条件
     * @param int $page 页数
     * @param int $limit 条数
     * @return  array
     * */
    public function getGroupChatList($condition = [], $page = 0, $limit = 10)
    {
        $db = DB::table($this->table)->where($condition);

        // 总条数
        $totalCount = $db->count($this->primaryKey);

        // 查询数据
        $list = $db->offset($page * $limit)->limit($limit)->get()->toArray();
        $list = self::objToArray($list);

        foreach ($list as $key => $value) {
            if (!empty($value['group_chat_image'])) {
                $list[$key]['group_chat_image'] = build_image($value['group_chat_image']);
            }
        }

        return $this->checkPageData($page, $limit, $totalCount, $list);
    }

    /**
     * 根据群聊ID组查询群聊数据
     * @param array $groupChatIdArray 群聊ID组
     * @return array
     * */
    public function getGroupChatByIdArray($groupChatIdArray)
    {
        do {
            if (empty($groupChatIdArray)) {
                $data = [];
                break;
            }

            $data = Redis::MGET(array_map(function ($groupChatId) {
                return $this->redisKeyGroupChat . $groupChatId;
            }, $groupChatIdArray));

            foreach ($data as $key => $value) {
                if (empty($value)) {
                    unset($data[$key]);
                    continue;
                }

                unset($groupChatIdArray[$key]);

                $value = json_decode($value, true);
                $value['group_chat_image'] = build_image($value['group_chat_image']);
                $data[$key] = $value;
            }

            if (empty($groupChatIdArray)) {
                break;
            }

            $groupChat = DB::table($this->table)->whereIn('group_chat_id', $groupChatIdArray)->get()->toArray();
            $groupChat = self::objToArray($groupChat);
            if (empty($groupChat)) {
                break;
            }

            foreach ($groupChat as $key => $value) {
                $item['group_id'] = $this->groupPrefix . $value['group_chat_id'];
                $item = array_merge($item, $value);

                // 存储数据CACHE 24H
                Redis::setex($this->redisKeyGroupChat . $value['group_chat_id'], 24 * 3600, json_encode($item, JSON_UNESCAPED_UNICODE));

                $item['group_chat_image'] = build_image($item['group_chat_image']);
                $groupChat[$key] = $item;
            }

            $data = array_merge($data, $groupChat);

        } while (false);

        return $data;
    }

    /**
     * 检测群聊UID是否存在
     * @param int $groupChatUid 群聊UID
     * @return array
     * */
    public function checkGroupChatUidExists($groupChatUid)
    {
        $data = DB::table($this->table)->where(['group_chat_uid' => $groupChatUid])->first();
        $data = self::objToArray($data);
        if (empty($data)) {
            return [];
        }

        if (!empty($data['group_chat_image'])) {
            $data['group_chat_image'] = build_image($data['group_chat_image']);
        }

        return $data;
    }

    ####################################################################################################

    /**
     * 群聊成员-创建/更新/删除
     *
     * @param array $data 数据
     * @param string $type 操作类型 默认 insert=创建，delete=删除，deleteAll=删除所有
     * @param int $groupChatId 群聊ID
     * @param int $userId 用户ID
     * @return bool
     * */
    public function CUDGroupChatMember($data = [], $type = 'insert', $groupChatId = 0, $userId = 0)
    {
        $userIdArray = [];

        switch ($type) {
            case 'insert':
                $data['created_at'] = time();
                $data['updated_at'] = time();
                $ret = DB::table($this->groupChatMemberTable)->insertGetId($data);
                if ($ret and !empty($data['user_id'])) {
                    $userIdArray[] = $this->redisKeyGroupChatMember . $data['user_id'];
                }
                break;
            case 'update':
                $data['updated_at'] = time();
                $ret = DB::table($this->groupChatMemberTable)->where([$this->primaryKey => $groupChatId, 'user_id' => $userId])->update($data);
                if ($ret) {
                    $userIdArray[] = $this->redisKeyGroupChatMember . $userId;
                }
                break;
            case 'delete':
                $ret = DB::table($this->groupChatMemberTable)->where([$this->primaryKey => $groupChatId, 'user_id' => $userId])->delete();
                if ($ret) {
                    $userIdArray[] = $this->redisKeyGroupChatMember . $userId;

                    // 删除邀请记录
                    $this->CUDGroupChatReq([], 'delete', $userId, 0, $groupChatId);
                }
                break;
            case 'deleteAll':
                $getGroupChatMemberUserIdByGroupChatId = $this->getGroupChatMemberUserIdByGroupChatId($groupChatId);
                $ret = DB::table($this->groupChatMemberTable)->where([$this->primaryKey => $groupChatId])->delete();
                if ($ret) {
                    foreach ($getGroupChatMemberUserIdByGroupChatId as $value) {
                        $userIdArray[] = $this->redisKeyGroupChatMember . $value;

                        // 删除邀请记录
                        $this->CUDGroupChatReq([], 'delete', $value, 0, $groupChatId);
                    }
                }
                break;
            default:
                $ret = false;
                break;
        }

        if (!empty($userIdArray)) {
            Redis::DEL($userIdArray);
        }

        return $ret;
    }

    /**
     * 根据群成员设置消息通知属性 增加 群聊是否消息通知字段
     *
     * @param array $groupChatMemberData 群聊成员所在群聊数据
     * @param array $groupChatData 群聊数据
     * @return array
     * */
    public function addGroupChatIsMsgNoticeField($groupChatMemberData, $groupChatData)
    {
        $groupChatIdKeyIsMsgNoticeValueArray = array_column($groupChatMemberData, 'is_msg_notice', 'group_chat_id');
        foreach ($groupChatData as $key => $value) {
            $groupChatData[$key]['is_msg_notice'] = $groupChatIdKeyIsMsgNoticeValueArray[$value['group_chat_id']] ?? 1;
        }

        return $groupChatData;
    }

    /**
     * 根据用户ID获取用户所在群聊成员列表
     * @param int $userId 用户ID
     * @return  array
     * */
    public function getGroupChatMemberDataByUserId($userId)
    {
        do {
            if (Redis::exists($this->redisKeyGroupChatMember . $userId)) {
                $groupChatMemberData = Redis::hvals($this->redisKeyGroupChatMember . $userId);
                foreach ($groupChatMemberData as $key => $value) {
                    $groupChatMemberData[$key] = json_decode($value, true);
                }

                //根据字段 created_at 对数组进行降序排列
                $createdAt = array_column($groupChatMemberData, 'created_at');
                array_multisort($createdAt, SORT_DESC, $groupChatMemberData);
                break;
            }

            $groupChatMemberData = DB::table($this->groupChatMemberTable)->where(['user_id' => $userId])->orderBy('created_at', 'desc')->get()->toArray();
            $groupChatMemberData = self::objToArray($groupChatMemberData);
            if (empty($groupChatMemberData)) {
                break;
            }

            // cache store 24H
            $cacheData = [];
            foreach ($groupChatMemberData as $key => $value) {
                $cacheData[$value['group_chat_id']] = json_encode($value, JSON_UNESCAPED_UNICODE);
            }
            Redis::hmset($this->redisKeyGroupChatMember . $userId, $cacheData);
            if (Redis::ttl($this->redisKeyGroupChatMember . $userId) == -1) Redis::EXPIRE($this->redisKeyGroupChatMember . $userId, 24 * 3600);

        } while (false);

        return $groupChatMemberData;
    }

    /**
     * 根据用户ID、群聊ID查询群聊成员信息
     * @param int $userId 用户ID
     * @param int $groupChatId 群聊ID
     * @return  array
     * */
    public function getGroupChatMemberByUserIdAndGroupChatId($userId, $groupChatId)
    {
        $data = [];

        do {
            if (!Redis::exists($this->redisKeyGroupChatMember . $userId)) {
                $this->getGroupChatMemberDataByUserId($userId);
            }

            if (!Redis::hexists($this->redisKeyGroupChatMember . $userId, $groupChatId)) {
                break;
            }

            $data = json_decode(Redis::hget($this->redisKeyGroupChatMember . $userId, $groupChatId), true);

        } while (false);

        return $data;
    }

    /**
     * 根据群聊ID查询群聊下成员数量
     * @param int $groupChatId 群聊ID
     * @return  int
     * */
    public function getGroupChatMemberCountByGroupChatId($groupChatId)
    {
        return DB::table($this->groupChatMemberTable)->where(['group_chat_id' => $groupChatId])->count();
    }

    /**
     * 根据群聊ID查询群聊下所有成员信息（列表分页）
     * @param int $groupChatId 群聊ID
     * @param int $page 页数
     * @param int $limit 条数
     * @return  array
     * */
    public function getGroupChatMemberListByGroupChatId($groupChatId, $page = 0, $limit = 10)
    {
        $db = DB::table($this->groupChatMemberTable)->where(['group_chat_id' => $groupChatId]);

        // 总条数
        $totalCount = $db->count('group_chat_member_id');

        // 查询数据
        $list = $db->orderBy('member_type', 'desc')->orderBy('created_at', 'asc')->offset($page * $limit)->limit($limit)->get()->toArray();
        $list = self::objToArray($list);

        return $this->checkPageData($page, $limit, $totalCount, $list);
    }

    /**
     * 根据群聊ID查询群聊下所有成员用户ID
     * @param int $groupChatId 群聊ID
     * @param bool $isAdmin 是否获取所有 false=获取所有成员用户 true=只获取管理权限成员用户
     * @param bool $except_master 是否过滤掉群主
     * @return  array
     * */
    public function getGroupChatMemberUserIdByGroupChatId($groupChatId, $isAdmin = false ,$except_master=false)
    {
        $condition = [
            ['group_chat_id', '=', $groupChatId],
        ];
        if ($isAdmin && !$except_master) {
            $condition[] = ['member_type', '>', 0];
        } else{
            $condition[] = ['member_type', '!=', 2];
        }

        $data = DB::table($this->groupChatMemberTable)->where($condition)->get(['user_id'])->toArray();
        $data = self::objToArray($data);

        return array_column($data, 'user_id');
    }

    ####################################################################################################

    /**
     * 群聊成员请求-创建/更新/删除
     *
     * @param array $data 数据
     * @param string $type 操作类型 默认 insert=创建，delete=删除，increment=累加
     * @param int $userId 用户ID（接收用户ID）
     * @param int $reqUserId 用户ID（请求用户ID）
     * @param int $groupChatId 群聊ID
     * @return bool
     * */
    public function CUDGroupChatReq($data = [], $type = 'insert', $userId = 0, $reqUserId = 0, $groupChatId = 0)
    {
        // update / delete / increment
        $condition = ['user_id' => $userId];
        if ($reqUserId > 0) $condition['req_user_id'] = $reqUserId;
        if ($groupChatId > 0) $condition['group_chat_id'] = $groupChatId;

        $timestamp = time();
        switch ($type) {
            case 'insert':
                $data['created_at'] = $timestamp;
                $data['updated_at'] = $timestamp;
                $ret = DB::table($this->groupChatReqTable)->insertGetId($data);
                break;
            case 'update':
                $data['updated_at'] = time();
                $ret = DB::table($this->groupChatReqTable)->where($condition)->update($data);
                break;
            case 'delete':
                $ret = DB::table($this->groupChatReqTable)->where($condition)->delete();
                break;
            case 'increment':
                $ret = DB::table($this->groupChatReqTable)->where($condition)->increment('req_count', 1, ['updated_at' => $timestamp]);
                break;
            default:
                $ret = false;
                break;
        }

        return $ret;
    }

    /**
     * 查询群聊请求数据
     * @param int $userId 用户ID（接收用户ID）
     * @param int $reqUserId 用户ID（邀请用户ID）
     * @param int $groupChatId 群聊ID
     * @return  array
     * */
    public function getGroupChatReq($userId, $reqUserId = 0, $groupChatId = 0)
    {
        $condition = ['user_id' => $userId];
        if ($reqUserId > 0) $condition['req_user_id'] = $reqUserId;
        if ($groupChatId > 0) $condition['group_chat_id'] = $groupChatId;

        $data = DB::table($this->groupChatReqTable)->where($condition)->first();
        $data = self::objToArray($data);
        if (empty($data)) {
            return [];
        }

        return $data;
    }

    /**
     * 根据群聊ID查询群聊下所有请求信息（列表分页）
     * @param int $groupChatId 群聊ID
     * @param int $page 页数
     * @param int $limit 条数
     * @return  array
     * */
    public function getGroupChatReqListByGroupChatId($groupChatId, $page = 0, $limit = 10)
    {
        $db = DB::table($this->groupChatReqTable)->where([['group_chat_id', '=', $groupChatId], ['is_admin_op_state', '=', 0]]);

        // 总条数
        $totalCount = $db->count('req_id');

        // 查询数据
        $list = $db->orderBy('created_at', 'asc')->offset($page * $limit)->limit($limit)->get()->toArray();
        $list = self::objToArray($list);

        return $this->checkPageData($page, $limit, $totalCount, $list);
    }

    ####################################################################################################

    /**
     * 房间与群聊绑定
     *
     * @param $userId int 用户ID
     * @param $roomId int 房间ID
     * @param $groupChatId int 群聊ID
     *
     * @return bool
     * */
    public function roomBindGroupChat($userId, $roomId, $groupChatId)
    {
        $check = DB::table($this->groupChatRoomTable)->where(['room_id' => $roomId, 'group_chat_id' => $groupChatId])->count();
        if (!empty($check)) {
            return true;
        }

        $timestamp = time();

        $ret = DB::table($this->groupChatRoomTable)->insertGetId([
            'user_id' => $userId,
            'room_id' => $roomId,
            'group_chat_id' => $groupChatId,
            'created_at' => $timestamp,
            'updated_at' => $timestamp,
        ]);

        /*if ($ret) {
            // 增加到redis hash表中
            $redisKeyGroupChatBindRoomHash = sprintf($this->redisKeyGroupChatBindRoomHash, $groupChatId);
            Redis::HSET($redisKeyGroupChatBindRoomHash, $roomId, $timestamp);
        }*/

        return $ret;
    }

    /**
     * 删除房间与群聊的绑定
     *
     * @param $groupChatId int 群聊ID
     *
     * @return bool
     * */
    public function deleteRoomBindGroupChat($groupChatId)
    {
        $ret = DB::table($this->groupChatRoomTable)->where(['group_chat_id' => $groupChatId])->delete();

        // 删除 redis hash表
        $redisKeyGroupChatBindRoomHash = sprintf($this->redisKeyGroupChatBindRoomHash, $groupChatId);

        if ($ret and Redis::exists($redisKeyGroupChatBindRoomHash)) {
            Redis::DEL($redisKeyGroupChatBindRoomHash);
        }

        return $ret;
    }

    /**
     * 根据群聊ID获取房间ID组
     *
     * @param $groupChatId int 群聊ID
     *
     * @return array
     * */
    public function getRoomIdArrayByGroupChatId($groupChatId)
    {
        $roomIdArray = [];

        // redis hash表
        $redisKeyGroupChatBindRoomHash = sprintf($this->redisKeyGroupChatBindRoomHash, $groupChatId);

        do {
            if (Redis::exists($redisKeyGroupChatBindRoomHash)) {
                $roomIdArray = Redis::hkeys($redisKeyGroupChatBindRoomHash);
                break;
            }

            $groupChatRoom = DB::table($this->groupChatRoomTable)->where(['group_chat_id' => $groupChatId])->get()->toArray();
            $groupChatRoom = self::objToArray($groupChatRoom);
            if (empty($groupChatRoom)) {
                break;
            }

            $roomIdArray = array_column($groupChatRoom, 'room_id');

            // 增加到redis hash表
            $cacheData = [];
            foreach ($groupChatRoom as $key => $value) {
                $cacheData[$value['room_id']] = $value['created_at'];
            }
            Redis::HMSET($redisKeyGroupChatBindRoomHash, $cacheData);

        } while (false);

        if (Redis::TTL($redisKeyGroupChatBindRoomHash) == -1) {
            Redis::EXPIRE($redisKeyGroupChatBindRoomHash, 3600);
        }

        return $roomIdArray;
    }

    ####################################################################################################

    /**
     * 群聊举报请求-创建/更新/删除
     *
     * @param array $data 数据
     * @param string $type 操作类型 默认 insert=创建，delete=删除，increment=累加
     * @param int $groupChatId 群聊ID
     * @return bool
     * */
    public function CUDGroupChatReport($data = [], $type = 'insert', $groupChatId = 0)
    {
        switch ($type) {
            case 'insert':
                $data['created_at'] = time();
                $ret = DB::table($this->groupChatReportTable)->insertGetId($data);
                break;
            case 'delete':
                $ret = DB::table($this->groupChatReportTable)->where(['group_chat_id' => $groupChatId])->delete();
                break;
            default:
                $ret = false;
                break;
        }

        return $ret;
    }


    ####################################################################################################

    /**
     * 公会与群聊绑定
     *
     * @param $userId int 用户ID
     * @param $unionId int 公会ID
     * @param $groupChatId int 群聊ID
     *
     * @return bool
     * */
    public function unionBindGroupChat($userId, $unionId, $groupChatId)
    {
        $check = DB::table($this->groupChatUnionTable)->where(['union_id' => $unionId, 'group_chat_id' => $groupChatId])->count();
        if (!empty($check)) {
            return true;
        }

        $ret = DB::table($this->groupChatUnionTable)->insertGetId([
            'user_id' => $userId,
            'union_id' => $unionId,
            'group_chat_id' => $groupChatId,
        ]);
        return $ret;
    }

    /**
     * 删除公会与群聊的绑定
     *
     * @param $groupChatId int 群聊ID
     *
     * @return bool
     * */
    public function deleteUnionBindGroupChat($unionId)
    {
        $ret = DB::table($this->groupChatUnionTable)->where(['union_id' => $unionId])->delete();
        return $ret;
    }


    /**
     * 通过公会ID获取聊天组ID
     * @param $unionId
     * @return mixed|null
     */
    public function getGroupChatByUnion($unionId){
        $result = DB::table($this->groupChatUnionTable)
            ->where(['union_id'=>$unionId])
            ->first();
        if (empty($result)){
            return null;
        }
        $result = $this->objToArray($result);
        return $result['group_chat_id'];
    }


    /**
     * 通过组Id获取公会ID
     * @param $groupChatId
     * @return null
     */
    public function getUnionByGroupChat($groupChatId){
        $result = DB::table($this->groupChatUnionTable)
            ->where(['group_chat_id'=>$groupChatId])
            ->first();
        if (empty($result)){
            return null;
        }
        $result = $this->objToArray($result);
        return $result['union_id'];
    }

    public function getGroupChatMembers(){
        $result = DB::table($this->groupChatMemberTable)->where("member_type", "!=", 2)->get();
        return $result = $this->objToArray($result);

    }

    /**
     * 通过userId  获取用户所在群列表
     * @param $userId
     * @return array
     */
    public function getGroupChatIdsByUserId($userId){
        $result = DB::table($this->groupChatMemberTable)
            ->where(['user_id'=>$userId])
            ->get();
        if (empty($result)){
            return null;
        }
        $result = $this->objToArray($result);
        return array_column($result, "group_chat_id");
    }

    /**创建家族群
     * @param $userId
     * @param $familyId
     * @param $groupChatId
     * @return bool|int
     */
    public function familyBindGroupChat($userId, $familyId, $groupChatId)
    {
        $check = DB::table($this->groupChatFamilyTable)->where(['family_id' => $familyId, 'group_chat_id' => $groupChatId])->count();
        if (!empty($check)) {
            return true;
        }

        return DB::table($this->groupChatFamilyTable)->insertGetId([
            'user_id' => $userId,
            'family_id' => $familyId,
            'group_chat_id' => $groupChatId,
        ]);
    }


    /**
     * 通过家族ID获取聊天组ID
     * @param $unionId
     * @return mixed|null
     */
    public function getGroupChatByFamily($familyId){
        $result = DB::table($this->groupChatFamilyTable)
            ->where(['family_id'=>$familyId])
            ->first();
        if (empty($result)){
            return null;
        }
        $result = $this->objToArray($result);
        return $result['group_chat_id'];
    }

    /**
     * 解散公会删除群聊
     *
     * @param $family_id int 家族id
     *
     * @return bool
     * */
    public function deleteFamilyBindGroupChat($family_id)
    {
        $ret = DB::table($this->groupChatFamilyTable)->where(['family_id' => $family_id])->delete();
        return $ret;
    }

    /**
     * 通过组Id获取家族id
     * @param $groupChatId
     * @return null
     */
    public function getFamilyByGroupChat($groupChatId){
        $result = DB::table($this->groupChatFamilyTable)
            ->where(['group_chat_id'=>$groupChatId])
            ->first();
        if (empty($result)){
            return null;
        }
        $result = $this->objToArray($result);
        return $result['family_id'];
    }

}